/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "quakedef.h"
#include "menu.shared.h"

struct level_t
{
	char *name;
	char *description;
};

level_t id1levels[] =
{
	{"dm1",		"The Place of Two Deaths"},
	{"dm2",		"Claustrophobopolis"},
	{"dm3",		"The Abandoned Base"},
	{"dm4",		"The Bad Place"},
	{"dm5",		"The Cistern"},
	{"dm6",		"The Dark Zone"},
	{"start",	"Introduction"},
	{"e1m1",	"The Slipgate Complex"},
	{"e1m2",	"Castle of the Damned"},
	{"e1m3",	"The Necropolis"},
	{"e1m4",	"The Grisly Grotto"},
	{"e1m5",	"Gloom Keep"},
	{"e1m6",	"The Door To Chthon"},
	{"e1m7",	"The House of Chthon"},
	{"e1m8",	"Ziggurat Vertigo"},
	{"e2m1",	"The Installation"},
	{"e2m2",	"The Ogre Citadel"},
	{"e2m3",	"The Crypt of Decay"},
	{"e2m4",	"The Ebon Fortress"},
	{"e2m5",	"The Wizard's Manse"},
	{"e2m6",	"The Dismal Oubliette"},
	{"e2m7",	"The Underearth"},
	{"e3m1",	"Termination Central"},
	{"e3m2",	"The Vaults of Zin"},
	{"e3m3",	"The Tomb of Terror"},
	{"e3m4",	"Satan's Dark Delight"},
	{"e3m5",	"The Wind Tunnels"},
	{"e3m6",	"The Chambers of Torment"},
	{"e3m7",	"The Haunted Halls"},
	{"e4m1",	"The Sewage System"},
	{"e4m2",	"The Tower of Despair"},
	{"e4m3",	"The Elder God Shrine"},
	{"e4m4",	"The Palace of Hate"},
	{"e4m5",	"Hell's Atrium"},
	{"e4m6",	"The Pain Maze"},
	{"e4m7",	"Azure Agony"},
	{"e4m8",	"The Nameless City"},
	{"end",		"Shub-Niggurath's Pit"}
};

// MED 01/06/97 added hipnotic levels
level_t hipnoticlevels[] =
{
	{"hipdm1",	"The Edge of Oblivion"},
	{"start",	"Command HQ"},
	{"hip1m1",	"The Pumping Station"},
	{"hip1m2",	"Storage Facility"},
	{"hip1m3",	"The Lost Mine"},
	{"hip1m4",	"Research Facility"},
	{"hip1m5",	"Military Complex"},
	{"hip2m1",	"Ancient Realms"},
	{"hip2m2",	"The Black Cathedral"},
	{"hip2m3",	"The Catacombs"},
	{"hip2m4",	"The Crypt"},
	{"hip2m5",	"Mortum's Keep"},
	{"hip2m6",	"The Gremlin's Domain"},
	{"hip3m1",	"Tur Torment"},
	{"hip3m2",	"Pandemonium"},
	{"hip3m3",	"Limbo"},
	{"hip3m4",	"The Gauntlet"},
	{"hipend",	"Armagon's Lair"}
};

// PGM 01/07/97 added rogue levels
level_t	roguelevels[] =
{
	{"start",	"Split Decision"},
	{"r1m1",	"Deviant's Domain"},
	{"r1m2",	"Dread Portal"},
	{"r1m3",	"Judgement Call"},
	{"r1m4",	"Cave of Death"},
	{"r1m5",	"Towers of Wrath"},
	{"r1m6",	"Temple of Pain"},
	{"r1m7",	"Tomb of the Overlord"},
	{"r2m1",	"Tempus Fugit"},
	{"r2m2",	"Elemental Fury I"},
	{"r2m3",	"Elemental Fury II"},
	{"r2m4",	"Curse of Osiris"},
	{"r2m5",	"Wizard's Keep"},
	{"r2m6",	"Blood Sacrifice"},
	{"r2m7",	"Last Bastion"},
	{"r2m8",	"Source of Evil"},
	{"ctf1",    "Division of Change"}
};


int	startlevel;
int maxplayers;
int skilloption;
BOOL m_serverInfoMessage = FALSE;
double m_serverInfoMessageTime;


void M_BeginNewMultiPlayerGame (void)
{
	if (sv.active)
		Cbuf_AddText ("disconnect\n");

	Cbuf_AddText ("listen 0\n");	// so host_netport will be re-examined
	Cbuf_AddText (va ("maxplayers %u\n", maxplayers));
	Cvar_SetValue (skill, skilloption);

	SCR_BeginLoadingPlaque ();

	if (hipnotic)
		Cbuf_AddText (va ("map %s\n", hipnoticlevels[startlevel].name));
	else if (rogue)
		Cbuf_AddText (va ("map %s\n", roguelevels[startlevel].name));
	else Cbuf_AddText (va ("map %s\n", id1levels[startlevel].name));
}


class qmenu_gameoptions_t : public qmenu_t
{
private:
	class qmenu_maxplayers_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			return va ("%i", maxplayers);
		}

		void SetFunc (int dir)
		{
			maxplayers += dir;

			if (maxplayers > svs.maxclientslimit)
			{
				maxplayers = 2;
				m_serverInfoMessage = TRUE;
				m_serverInfoMessageTime = realtime;
			}

			if (maxplayers < 2) maxplayers = svs.maxclientslimit;
		}
	} maxplayers_watcher;

	class qmenu_gametype_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			return coop->boolean ? "Cooperative" : "Deathmatch";
		}

		void SetFunc (int dir)
		{
			Cvar_SetValue (coop, coop->value ? 0 : 1);
		}
	} gametype_watcher;

	class qmenu_teamplay_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			if (rogue)
			{
				switch (teamplay->integer)
				{
				case 1: return "No Friendly Fire";
				case 2: return "Friendly Fire";
				case 3: return "Tag";
				case 4: return "Capture the Flag";
				case 5: return "One Flag CTF";
				case 6: return "Three Team CTF";
				default: return "Off";
				}
			}
			else
			{
				switch (teamplay->integer)
				{
				case 1: return "No Friendly Fire";
				case 2: return "Friendly Fire";
				default: return "Off";
				}
			}
		}

		void SetFunc (int dir)
		{
			M_AdjustCvar (teamplay, dir, 0, rogue ? 6 : 2);
		}
	} teamplay_watcher;

	class qmenu_skill_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			return M_GetSkill (skilloption);
		}

		void SetFunc (int dir)
		{
			skilloption += dir;

			if (skilloption < 0) skilloption = 3;
			if (skilloption > 3) skilloption = 0;
		}
	} skill_watcher;

	class qmenu_fraglimit_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			if (fraglimit->integer > 0)
				return va ("%i frags", fraglimit->integer);
			else return "none";
		}

		void SetFunc (int dir)
		{
			M_AdjustCvar (fraglimit, dir * 10, 0, 100);
		}
	} fraglimit_watcher;

	class qmenu_timelimit_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			if (timelimit->integer > 0)
				return va ("%i minutes", timelimit->integer);
			else return "none";
		}

		void SetFunc (int dir)
		{
			M_AdjustCvar (timelimit, dir * 5, 0, 60);
		}
	} timelimit_watcher;

	class qmenu_map_watcher_t : public qmenu_stringoptionwatcher_t
	{
		char *GetFunc (void)
		{
			if (hipnotic)
				return hipnoticlevels[startlevel].name;
			else if (rogue)
				return roguelevels[startlevel].name;
			else return id1levels[startlevel].name;
		}

		void SetFunc (int dir)
		{
			int maxlevels = 0;

			if (hipnotic)
				maxlevels = sizeof (hipnoticlevels) / sizeof (hipnoticlevels[0]);
			else if (rogue)
				maxlevels = sizeof (roguelevels) / sizeof (roguelevels[0]);
			else maxlevels = sizeof (id1levels) / sizeof (id1levels[0]);

			startlevel += dir;

			if (startlevel < 0) startlevel = maxlevels - 1;
			if (startlevel >= maxlevels) startlevel = 0;
		}
	} map_watcher;

public:
	qmenu_gameoptions_t (void)
	{
		// add our options
		this->AddOption (new qmenu_banner_t ("gfx/p_multi.lmp"));
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_action_t ("Begin game", M_BeginNewMultiPlayerGame));
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_stringoption_t ("Max players", maxplayers_watcher));
		this->AddOption (new qmenu_stringoption_t ("Game type", gametype_watcher));
		this->AddOption (new qmenu_stringoption_t ("Teamplay", teamplay_watcher));
		this->AddOption (new qmenu_stringoption_t ("Skill", skill_watcher));
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_stringoption_t ("Frag limit", fraglimit_watcher));
		this->AddOption (new qmenu_stringoption_t ("Time limit", timelimit_watcher));
		this->AddOption (new qmenu_divider_t ());

		this->AddOption (new qmenu_stringoption_t ("Map", map_watcher));
		this->AddOption (new qmenu_dynamictext_t (this->DynamicText));

		// and register the menu
		this->Register (m_gameoptions);
	}

	void EnterFunc (void)
	{
		this->EnterMenu ();

		// sync up values
		if (maxplayers == 0) maxplayers = svs.maxclients;
		if (maxplayers < 2) maxplayers = svs.maxclientslimit;

		// begin with normal skill
		skilloption = 1;
	}

protected:
	void CustomDraw (void)
	{
		// update the map description
		if (hipnotic)
			Q_strncpy (this->DynamicText, hipnoticlevels[startlevel].description, sizeof (this->DynamicText) - 1);
		else if (rogue)
			Q_strncpy (this->DynamicText, roguelevels[startlevel].description, sizeof (this->DynamicText) - 1);
		else Q_strncpy (this->DynamicText, id1levels[startlevel].description, sizeof (this->DynamicText) - 1);

		// display the optional server warning
		if (m_serverInfoMessage)
		{
			if ((realtime - m_serverInfoMessageTime) < 5.0)
			{
				int y = 200;

				M_DrawTextBox ((320 - 28 * 8) / 2, y, 26, 5);

				M_DrawCommand ((y = y + 8), "More than 4 players");
				M_DrawCommand ((y = y + 8), "requires using command");
				M_DrawCommand ((y = y + 8), "line parameters; please");
				M_DrawCommand ((y = y + 8), "see techinfo.txt.");
			}
			else m_serverInfoMessage = FALSE;
		}
	}

private:
	char DynamicText[128];
} menu_gameoptions;


